extends Object


class_name NodeHelper


# 获取对象中指定字段
static func get_usage_fields(obj: Object, usage_filter: Array) -> Array:
    return obj.get_property_list().filter(
        func(p):
            return usage_filter.filter(func(u): return p["usage"] & u == u).size() == usage_filter.size()
    ).map(func(x): return x["name"])

# 获取对象中用户自定义的属性字段
static func get_custom_fields(obj: Object) -> Array:
    return get_usage_fields(obj, [PROPERTY_USAGE_SCRIPT_VARIABLE, PROPERTY_USAGE_EDITOR])

# 返回对象的类名称(script名称)
static func get_class_name(target: Object) -> String:
    var script: Script = target.get_script() as Script
    if script == null || script.resource_path == "":
        return ""
    var r: String = script.resource_path
    var sTx: int = r.rfind('/') + 1
    var eTx: int = r.rfind('.')
    return r.substr(sTx, eTx - sTx)

# 返回两个对象是否是相同文件中的类
static func is_same_class_name(a: Object, b: Object) -> bool:
    return a.get_script() == b.get_script()

# 查找指定名称的节点,没有则自动创建
static func find_or_create(node: Node, node_name: String, visible: bool = false) -> Node:
    for c in node.get_children():
        if c.name == node_name:
            return c
    var n: Variant = null
    if visible:
        n = Node.new()
    else:
        n = Control.new()
        n.visible = false
    n.name = node_name
    node.call_deferred("add_child", n)
    return n

# 添加节点
static func add_child(parent: Node, node: Node, is_deferred: bool = false) -> Node:
    if node.get_parent():
        return reparent(node, parent, is_deferred)
    else:
        if is_deferred:
            parent.call_deferred("add_child", node)
        else:
            parent.add_child(node)
    return node

# 重置父节点
static func reparent(node: Node, parent: Node, is_deferred: bool = false) -> Node:
    if is_deferred:
        node.call_deferred("reparent", parent)
    else:
        node.reparent(parent)
    return node

# 将2D对象旋转至指定的坐标点
static func rotate_to_point(node: Node2D, point: Vector2) -> void:
    node.global_rotation = node.global_position.angle_to_point(point)

# 将2D对象旋转至鼠标
static func rotate_to_mouse(node: Node2D) -> void:
    rotate_to_point(node, node.get_global_mouse_position())

static func is_mouse_pressed(event: InputEvent, button_index: int = MOUSE_BUTTON_LEFT) -> bool:
    if event is InputEventMouseButton:
        var mouse: InputEventMouseButton = event as InputEventMouseButton
        if mouse.button_index == button_index and mouse.pressed:
            return true
    return false

static func is_mouse_released(event: InputEvent, button_index: int = MOUSE_BUTTON_LEFT) -> bool:
    if event is InputEventMouseButton:
        var mouse: InputEventMouseButton = event as InputEventMouseButton
        if mouse.button_index == button_index and not mouse.pressed:
            return true
    return false

static func print_orphan_nodes(msg: String) -> void:
    print(msg)
    Node.print_orphan_nodes()

# 批量设置可见性
static func set_visible(icons: Array, is_visable: bool) -> bool:
    for v in icons:
        if v:
            v.visible = is_visable
    return is_visable

# 获取碰撞层
static func get_tilemap_collision_layer(tilemap: TileMap, body_rid: RID) -> int:
    var hit_layer: int = 0
    var layer: int = tilemap.get_layer_for_body_rid(body_rid)
    var coords: Vector2i = tilemap.get_coords_for_body_rid(body_rid)
    var cell: TileData = tilemap.get_cell_tile_data(layer, coords)
    for i in range(tilemap.tile_set.get_physics_layers_count()):
        if cell.get_collision_polygons_count(i) > 0:
            hit_layer = tilemap.tile_set.get_physics_layer_collision_layer(i)
            break
    return hit_layer

static func replace_variable(fmt_string: String, values: Dictionary) -> String:
    var msg: String = fmt_string
    for k in values.keys():
        msg = msg.replace("${%s}" % k, str(values[k]))
    return msg

static func get_property_object(w: Node, property_list: Array) -> Array:
    var n: Variant = w
    if w and property_list.size() > 0:
        for i in range(0, property_list.size() - 1):
            var p: String = property_list[i] as String
            var idx: int = p.find('[')
            if idx > 0 and p.ends_with(']'):
                var word: String = p.get_slice('[', 1).rstrip(']')
                p = p.substr(0, idx)
                n = n.get(p)
                if word.length() > 2 and word[0] == "'" and word[-1] == "'":
                    var key: String = word.substr(1, word.length() - 2)
                    if n is Array:
                        var is_null: bool = true
                        for c in n:
                            if c.name == key:
                                n = c
                                is_null = false
                                break
                        if is_null:
                            return []
                    else:
                        if n is Dictionary:
                            n = n[key]
                        else:
                            return []
                else:
                    var index: int = int(word)
                    if n is Array:
                        n = n[index]
                    return []
            else:
                n = n.get(p)
            if n == null:
                return []
    return [n, property_list[-1]]

static func evaluate(node: Node, command: String, variable_names: Array = [], variable_values: Array = []) -> Variant:
    var expression: Expression = Expression.new()
    var error: Error = expression.parse(command, variable_names)
    if error != OK:
        push_error(expression.get_error_text())
        return

    var result: Variant = expression.execute(variable_values, node)
    if expression.has_execute_failed():
        push_error("has_execute_failed:", command)
        return null
    return result
